import axios, { AxiosResponse } from "axios";
import type {AxiosInstance,AxiosRequestConfig} from 'axios'
import { ElLoading } from 'element-plus'
//  定义拦截器 类型 实则就是一个个函数
interface WSInterceptors {
    // 不管是请求拦截 还是响应拦截  他都是一个函数而已
    requestInterceptor:(config:AxiosRequestConfig) => AxiosRequestConfig
    requestInterceptorCatch:(error:any) => any
    responseInterceptor:(res:AxiosResponse) => AxiosResponse
    responseInterceptorCatch:(error:any) => any
}
interface WSRequestConfig extends AxiosRequestConfig {
    // 这里相当于是满足了该类型是AxiosRequestConfig的同时，又扩展了其他属性，相当于拓展类型  满足axios.create(config)的需求
    interceptors?:WSInterceptors,
    showLoading?:boolean
}

const DEFAULT_SHOW_LOADING = true

export default class WSRequest {
  instance: AxiosInstance;
  interceptors?:WSInterceptors
  loadingInstance?:any
  showLoading:boolean
//   由于WSRequestConfig继承了AxiosRequestConfig  所以axios.create(config)中config需要的属性都有
  constructor(config: WSRequestConfig) {
    this.instance = axios.create(config);
    this.interceptors=config.interceptors
    this.showLoading = config.showLoading??DEFAULT_SHOW_LOADING
    // 由于创建实例时会执行constructor 所以可以在此处应用拦截器  但是此处应用的只是创建实例时传入的拦截器(一个个函数)
    this.instance.interceptors.request.use(this.interceptors?.requestInterceptor,this.interceptors?.requestInterceptorCatch)
    this.instance.interceptors.response.use(this.interceptors?.responseInterceptor,this.interceptors?.responseInterceptorCatch)
    // 注册通用拦截器 意味着创建实例时 不传 也会注册该拦截
    this.instance.interceptors.request.use(config => {
        if(this.showLoading) {
            this.loadingInstance = ElLoading.service({
                lock:true,
                text:'正在请求数据...',
                background: 'rgba(0,0,0,0.5)'
            })
        }
        return config
    },err => {
        console.log(err);    
    })

    this.instance.interceptors.response.use(res => {
            this.loadingInstance?.close()
        return res.data
    },err => {
        this.loadingInstance?.close()
        console.log(err);  
    })
  }
//   此处采用自定义的WSRequestConfig中含有拦截器选项，可以自行配置拦截器
  request(config:WSRequestConfig){
    return new Promise((resolve,reject) => {
        // 每一次具体请求进行拦截
    if(config.interceptors?.requestInterceptor){
        // requestInterceptor 该函数会返回一个config
        config = config.interceptors?.requestInterceptor(config)
    }
    if(config.showLoading === false){
        this.showLoading = config.showLoading
    }
    this.instance.request(config).then(res => {
        if(config.interceptors?.responseInterceptor){
            res = config.interceptors?.responseInterceptor(res)
        }
        this.showLoading = DEFAULT_SHOW_LOADING
        console.log(res);
        resolve(res)
    }).catch(err => {
        reject(err)
    })
    })
  }


  get(config: WSRequestConfig) {
    return this.request({ ...config, method: 'GET' })
  }

  post(config: WSRequestConfig) {
    return this.request({ ...config, method: 'POST' })
  }

  delete(config: WSRequestConfig) {
    return this.request({ ...config, method: 'DELETE' })
  }

  patch(config: WSRequestConfig) {
    return this.request({ ...config, method: 'PATCH' })
  }

/* 
  汇总：
    1.封装一个request类
        类里面含有两个成员变量
         instance: AxiosInstance  用来发送请求 注册拦截器
         interceptors?:WSInterceptors 可选参数  具体看创建实力时是否传入
    2.拦截器一共有三种触发方式
        （1）在创建实例时传入，那么每次调用实例方法时，都会触发该拦截
        （2）在调用实例方法时传入，相当于可以自定义每次请求的拦截
        （3）都不传入，则会调用通用拦截器，无论如何都会执行
 */
}
